"""
Copyright (c) 2022 Huawei Technologies Co.,Ltd.
"""

"""
Case Type   : 资源池化
Case Name   : 资源池化场景下，主备节点业务压力，构造failover场景
Create At   : 2024-11-22
Owner       : zhongchengzhi
Description :
    1、查询集群状态
    2、运行tpcc业务，主节点读写，备节点只读
    3、主节点注入dn故障
    4、查询集群状态
    5、升主节点运行tpcc状态
    6、停止tpcc业务运行
    7、恢复原主节点运行
    8、恢复集群初始状态

Expect      :
    1、查询结果正常
    2、tpcc运行正常
    3、注入故障成功，开始failover
    4、升主节点运行正常，备节点运行正常
    5、升主节点运行tpcc业务正常
    6、停止tpcc业务运行正常
    7、恢复原主节点成功
    8、恢复集群初始状态成功，集群正常运行
History     :
    1、2024-11-22 创建
    2、2025-07-11 改造用例为1p1s环境可执行
"""

import os
import re
import time
import unittest
from yat.test import Node
from yat.test import macro
from testcase.utils.Logger import Logger
from testcase.utils.Common import Common
from testcase.utils.CommonSH import CommonSH
from testcase.utils.Constant import Constant
from testcase.utils.ComThread import ComThread

Primary_ROOTSH = CommonSH('PrimaryRoot')
Primary_SH = CommonSH('PrimaryDbUser')
Standby1_SH = CommonSH('Standby1DbUser')

@unittest.skipIf(1 == Primary_SH.get_node_num(), '单机环境不执行')
class SharedStorage(unittest.TestCase):
    def setUp(self):
        self.log = Logger()
        self.com = Common()
        self.constant = Constant()
        self.primary_root = Node(node="PrimaryRoot")
        self.pri_user_node = Node(node="PrimaryDbUser")
        self.standby_node1 = Node(node="Standby1DbUser")
        self.log.info(f'-----{os.path.basename(__file__)} start-----')

    def test_shared_storage(self):
        text = '======step1:查看集群状态; expect:集群状态正常======'
        self.log.info(text)
        status = Primary_SH.exec_cm_ctl(mode='query', param='-Cvipd')
        self.log.info(status)
        self.assertIn('cluster_state   : Normal', status, '执行失败' + text)

        self.log.info("查询数据库进程号")
        pid1 = self.com.get_pid(self.standby_node1, 'bin/gaussdb')
        self.log.info("备1节点进程号:" + pid1)

        text = '======step2:运行tpcc业务,主机读写,备机只读;expect:tpcc进程运行正常======'
        self.log.info(text)
        primary_tpcc = ComThread(self.com.start_tpcc,
                                 args=(self.primary_root,
                                       macro.TPCC_PATH,
                                       './runBenchmark.sh primary_write.pg'))
        standby1_tpcc = ComThread(self.com.start_tpcc,
                                  args=(self.primary_root,
                                        macro.TPCC_PATH,
                                        './runBenchmark.sh standby_read1.pg'))
        primary_tpcc.setDaemon(True)
        standby1_tpcc.setDaemon(True)
        primary_tpcc.start()
        standby1_tpcc.start()
        status = Primary_ROOTSH.exec_cmd_under_root("ps -ux | grep './runBenchmark.sh' | grep -v -- '--color'")
        self.assertIn('primary_write.pg', status, '执行失败' + text)
        status = Primary_ROOTSH.exec_cmd_under_root("ps -ux | grep './runBenchmark.sh' | grep -v -- '--color'")
        self.assertIn('standby_read1.pg', status, '执行失败' + text)
        time.sleep(30)

        text = '-----step3:主节点注入dn故障; expect:主节点down，触发failover-----'
        self.log.info(text)
        stopdn = Primary_SH.exec_failover()
        self.log.info(stopdn)
        time.sleep(180)

        text = '-----step4:查询集群状态 expect:一个备节点成功升主，一个为Standby Normal-----'
        self.log.info(text)
        status = Primary_SH.exec_cm_ctl(mode='query', param='-Cvipd')
        self.log.info(status)
        self.assertIn('cluster_state   : Degraded', status, '执行失败' + text)
        res1 = status.splitlines()[-1].split('|')[0].split('6001')[-1]
        res2 = status.splitlines()[-1].split('|')[1].split('6002')[-1]
        self.assertIn('P Down    Manually stopped', res1, '执行失败' + text)
        self.assertIn('S Primary Normal', res2, '执行失败' + text)

        text = '-----step5:升主节点运行tpcc业务 expect:升主节点运行tpcc业务正常-----'
        self.log.info(text)
        primary_tpcc = ComThread(self.com.start_tpcc,
                                 args=(self.primary_root,
                                       macro.TPCC_PATH,
                                       './runBenchmark.sh primary_write.pg'))
        primary_tpcc.setDaemon(True)
        primary_tpcc.start()
        status = Primary_ROOTSH.exec_cmd_under_root("ps -ux | grep './runBenchmark.sh' | grep -v -- '--color'")
        self.assertIn('primary_write.pg', status, '执行失败' + text)
        time.sleep(30)

    def tearDown(self):
        text = '======step6:停止tpcc进程; expect:成功======'
        self.log.info(text)
        status = Primary_SH.exec_cm_ctl(mode='query', param='-Cv')
        self.log.info(status)
        status = Primary_SH.check_cluster_core_status(status, wait_times=600)
        self.log.info(status)
        stop_tpcc_cmd = "ps -ef | grep runBenchmark | grep -v grep | " \
                        + "awk '{{print $2}}' | xargs kill -9"
        status = Primary_ROOTSH.exec_cmd_under_root(stop_tpcc_cmd)
        self.log.info(status)
        status = Primary_SH.exec_cm_ctl(mode='stop')
        self.log.info(status)
        self.assertIn(self.constant.cm_stop_success_msg, status,
                      '执行失败' + text)

        text = '======step7:恢复原主节点运行; expect:成功======'
        self.log.info(text)
        startdn = Primary_SH.exec_cm_ctl('start')
        self.log.info(startdn)
        self.assertIn(self.constant.cm_start_success_msg, startdn, '拉起dn节点失败')
        status = Primary_SH.exec_cm_ctl(mode='query', param='-Cvipd')
        self.assertIn('cluster_state   : Normal', status, '执行失败' + text)
        
        text = '======step8:恢复集群到初始状态; expect:成功======'
        recovery = Primary_SH.exec_cm_ctl(mode='switchover', param='-a')
        self.log.info(recovery)
        self.assertIn(self.constant.cm_switchover_success_msg, recovery,
                      '执行失败' + text)

        status = Primary_SH.exec_cm_ctl(mode='query', param='-Cvipd')
        self.log.info(status)
        self.assertIn('cluster_state   : Normal', status, '执行失败' + text)
        self.assertIn('P Primary Normal',
                      status.splitlines()[-1].split('|')[0].split('6001')[-1],
                      '执行失败' + text)
        self.assertIn('S Standby Normal',
                      status.splitlines()[-1].split('|')[1].split('6002')[-1],
                      '执行失败' + text)

        self.log.info(f"-----{os.path.basename(__file__)} end-----")
